package com.jse.api;

import java.io.IOException;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;

import com.jse.Http;
import com.jse.Lang;
import com.jse.json.Json;
import com.jse.json.JsonObject;

public class WxPay3 {
	/**
	 * @param param 
	{
		"mchid": "1900006XXX",
		"out_trade_no": "1217752501201407033233368318",
		"appid": "wxdace645e0bc2cXXX",
		"description": "Image形象店-深圳腾大-QQ公仔",
		"notify_url": "https://www.weixin.qq.com/wxpay/pay.php",
		"amount": {
			"total": 1,
			"currency": "CNY"
		},
		"payer": {
			"openid": "o4GgauInH_RCEdvrrNGrntXDuXXX"
		}
	}
	 */
	public static String pay(Map param) {
		String type=param.remove("type").toString();//app,h5,native
		String privateKey=param.remove("privateKey").toString();
		if(!param.containsKey("Authorization")) {
			//WECHATPAY2-SHA256-RSA2048 mchid="1900009191",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==",timestamp="1554208460",serial_no="1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C"
			//WECHATPAY2-SHA256-RSA2048 mchid="1289729501",nonce_str="e338705fc4334db3b25d63099ec60435",timestamp="1719999537",serial_no="19D79DA72417BC22B246EDF5D1D50D48E9771342",signature="DzP/hlrvvHdSi2Te5vGyWtLfXL4HUiJ9fqAX/3LTqjJ8KFa+YofQtTAd57EaICWAmcFzGUWDNJj2U7NbJccdTLu4JNcUZDu+zR7YP72d0RgCOmsJp3w8SM5ab77gGsnQzp9a3GX6gumpxpX4uBfWKtSM4mvIHFFKrypyir6d80+h/b9k5SwILfF9IdeEkLBqBRTn76At9c1x3slb/UTN4k9aBdUaVwtcLwiaVPUvs3MW62+6rXxdwDBsseaNI1JCHLoNgFMaTvCR4vAs4gYs/r/1GZ3E/o9dOnDZFzm2eMzcLNaVw1dFNmJZ0pARWH2kV+2IJGoIZmKarl8HC+No3w=="
			String x="WECHATPAY2-SHA256-RSA2048 "+getToken("POST",param.get("mchid").toString(),privateKey,
					param.remove("serial_no").toString(),
					URI.create("/v3/pay/transactions/"+type),Json.toJson(param));
			param.put("#Authorization",x);
		}
		return Http.postJson("https://api.mch.weixin.qq.com/v3/pay/transactions/"+type,param);
	}
	public static String jsquery(Map param) {
		if(param.containsKey("transaction_id")){
			Http.get("https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s?mchid=%s"
					.formatted(param.get("transaction_id"),param.get("mchid")));
		}
		return Http.get("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s"
				.formatted(param.get("transaction_id"),param.get("mchid")));
	}
	/** JSAPI关闭订单 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml */
	public static String jsclose(String out_trade_no,String mchid) {
		return Http.postJson("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close"
				.formatted(out_trade_no),
				Map.of("mchid",mchid));
	}
	public static String jsbill(String date,String mchid) {
		return Http.postJson("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=%s"
				.formatted(date),
				Map.of("mchid",mchid));
	}
	public static String getToken(String method,String mchid,String privateKey,String serial_no,URI url, String body){
		try {
			String nonceStr = Lang.uuid();
		    long timestamp = System.currentTimeMillis() / 1000;
		    String message = buildMessage(method, url, timestamp, nonceStr, body);
		    String signature = sign(message.getBytes("utf-8"),getPrivateKey(privateKey));
		    return "mchid=\"" + mchid + "\","
		    + "nonce_str=\"" + nonceStr + "\","
		    + "timestamp=\"" + timestamp + "\","
		    + "serial_no=\"" + serial_no + "\","
		    + "signature=\"" + signature + "\"";
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	private static String sign(byte[] message,PrivateKey privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
	    Signature sign = Signature.getInstance("SHA256withRSA");
	    sign.initSign(privateKey);
	    sign.update(message);
	    return Base64.getEncoder().encodeToString(sign.sign());
	}
	private static String buildMessage(String method, URI url, long timestamp, String nonceStr, String body) {
	    String canonicalUrl = url.getPath();
	    if (url.getQuery() != null) {
	      canonicalUrl += "?" + url.getQuery();
	    }
	    return method + "\n"
	        + canonicalUrl + "\n"
	        + timestamp + "\n"
	        + nonceStr + "\n"
	        + body + "\n";
	}
	public static PrivateKey getPrivateKey(String filename) throws IOException {
		  String content = """
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDJHMAd0AaGNlop
kPVPx6nt6BIMcTwAhK7hSydsxXwchtnQ083mP6uZvrnzkf20XMoXkF5CoUhKmOei
wAd1a2DUdUIVq+gOzrh1nvgdWBYpjWhZ96O1HvYmMi2wBZCaMomiEHwbu2at8K3j
L9xMS/qCZrgbSW7oYHxZLtdsq0Oh+Mo6ZmPlIyyIcRl4/oHwP0hla26KiLBFRSiJ
lg4Aed6kntkZ9fTy5iMTPgU7nMY8skQjiC9nZjpaROeWzg+zxICqL696ggAFKbiq
wJehm/D0Um338T6UtmYr7rzZpMoAHIZLkA/fkByKQJ/PgJZwFRguv3TzdrxErKLT
oW4bcQu9AgMBAAECggEBAJKeXkWd2pPQXk09fEqskut6LGZby1XJZcGkS9rV4xTd
D0FamRrKwm01ClZT0fXDTCZ/vuiusoiIDx+tBgMJxK8/yW0JRgY9mWdO/S5PgODM
Ug59JyGtr+DK5loUxIZWX9cCU6jYKBSZifw+cUpCfiDBiGmEUNIjPaS7LJzyAz26
W0dYNUWlfeOAGyvzVOyADLZ01k3MKMsCDBoUH3H7lQxWbJdOQf8Cg9KMoWD8CJog
5OANs3OqBR188n61LIVYAG7Va6+t8MtNerHfB2ZnLUg6Zb9t3MI9RWPTkocmhHQe
kkfkD9il8GQd6kpqRv4b4PxlqNPWb5md5J3L4/VwA9UCgYEA749Fbic1G14Ftdu5
5eEOBTj3ZcvKA4sCRRqDWj5EK+6U6077TGLBD2sJNuPBAU9N5nejnlkFR3B6cDUA
V11FSqYZZh3wAqy/4KePdVvi2ge6AUw6gS2R87YNSOknIoUH9UNsozgAqxnJl6cD
2KH3hM/8QRwMvVFRRNNTGO2LCacCgYEA1uoDVQ0D7MIT6SgpKqW8gqhsfGvEsEdv
TkAWaDiQAc5tBohAWo3x//XwEDCTpbtubv6BOf9Utl7WC4m7syuEgCOzNt2Ae4UI
jv3iNYQXqPRSyAPRSwkpsHD6cjG2q7yq4hXOB63eKwTPcot9SSdsZDEEjYghWYm/
fw0PiGvlY/sCgYEAu8VYDYxL0ySyYyZUIvxxieRp/m9q67YE1HeAp7aQpsK+FWb2
EJyDaPtj4JNKkCVCETiLli1+ts1SGytgFhp0mptw4xrqKp6PU57jEoEwYeeWgzfl
z6URdq6m4RRnaWZOo47y00itNW/kFKuDl0T1BzQjLEG5NpdLlR/zTWG8DpcCgYEA
i8NLv3fjYYklYa+Ydf+qhF37jz6Wfv01yXGsIMMIA+S2ylS5ZSqCgq7yG9U7b8Bg
pRYl/A2sjZ1HHeHIi1B1rs+IsNmDwNBXLIa3IY5xxJJ/c0voRCAFWJVgifsCjNT5
XGZJwnyzys4qCpfkNjrJJq8qAtDQv2XxfzKDM3jXiRkCgYBQjxwlKwuSLtZoARUl
ioyN/PJDz5Vba7G5zJtSE3uAeMZL7d/+6/opl9XZwNWWq6qH6hl9nh+I9UdC35Gg
1Y4pPDgsiRtno356AGsqJKPCYR2z4AoKgT82icM+DM28TEWe4moDisGOtjBGt2bn
A7wIezp7xfCUbX63VLJmM21KQw==
-----END PRIVATE KEY-----""";
		  try {
		    String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
		            .replace("-----END PRIVATE KEY-----", "")
		        .replaceAll("\\s+", "");
		    KeyFactory kf = KeyFactory.getInstance("RSA");
		    return kf.generatePrivate(
		        new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
		  } catch (NoSuchAlgorithmException e) {
		    throw new RuntimeException("当前Java环境不支持RSA", e);
		  } catch (InvalidKeySpecException e) {
		    throw new RuntimeException("无效的密钥格式");
		  } catch (Exception e) {
			throw e;
		  }
		}

//	public static PrivateKey getPrivateKey(String key) {
//	    try {
//	        byte[] byteKey = Base64.getDecoder().decode(key);
//	        PKCS8EncodedKeySpec x509EncodedKeySpec = new PKCS8EncodedKeySpec(byteKey);
//	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//	        return keyFactory.generatePrivate(x509EncodedKeySpec);
//	    } catch (Exception e) {
//	        e.printStackTrace();
//	    }
//	    return null;
//	}
	
	public static void main(String[] args) {
		String x=pay(Json.parse("""
				{
	"appid": "wx2787c3302c182d65",
	"mchid":"1289729501",
	"notify_url": "https://www.iepsy.com/pay/wx/notify",
	"description": "ajsh2",
	"out_trade_no": "20240703155713015126505-17199972",
	"amount": {
      "total" : 100,
      "currency" : "CNY"
    },
    "payer": {
			"openid": "oHStSs6yhUmW66hrkqiQ20xKLCQc"
		},
	"type":"jsapi",
	"privateKey":"6e332d87778242619fd832c1bc85d12f",
	"serial_no":"19D79DA72417BC22B246EDF5D1D50D48E9771342",
	"#Accept":"application/json",
	"#Content-Type":"application/json"
}
				""".trim(), JsonObject.class));
//		tab.put("type","jsapi")
//		tab.put("privateKey","srUsvUgVfjGXvPDzyyFcHteYQ4snprlV")
//		tab.put("mchid","1289729501")
//		tab.put("serial_no","19D79DA72417BC22B246EDF5D1D50D48E9771342")
		System.out.println(x);
	}
}
